#ifndef IGSLIB_SERIAL_MANAGER_H
#define IGSLIB_SERIAL_MANAGER_H

#include <set>
#include <string>
#include <vector>
#include "igslib_iserial_manager.h"

namespace igslib 
{
	class CSerial:virtual public ISerial
	{
        protected:
            std::string name;
            std::set<ISerialEvent*> events;
        public:
            virtual void SetEventHandler(ISerialEvent* value) { events.insert(value); }
            virtual void SetName(std::string value) { name = value; }
            virtual std::string GetName() { return name; }
            virtual void FlushBuffer() { }
            virtual int Send(char*,int) { return 0; }
            virtual int ReSend() { return 0; }
            virtual int Receive(char*,int) { return 0; }
            virtual void Close() { }
            virtual int Update() { return 0; }
	};
    class CSpi:public CSerial,public ISpi
    {
        protected:
            std::vector<char> cache;
            int wf; ///< working frequency
        public:
            virtual bool FullDuplexReadWrite(char*,char*,int) { return false; }
			virtual bool HalfDuplexReadWrite(char*,int,char*,int) { return false; }
            virtual int Send(char* addr,int length)
            {
                cache.clear();
                cache.assign(addr,addr+length);
                return 0;
            }
            virtual int ReSend() { return Send(&cache[0],cache.size()); }
            virtual bool Open(ChipSelector) { return false; }
            virtual void SetWorkingFrequency(int value) { wf = value; }
            virtual int GetWorkingFrequency() { return wf; }
    };
    class CUart:public CSerial,virtual public IUart
    {
        protected:
            int br; // baud rate
            ParityMode pm;
            DataBits db;
            StopBits sb;
            std::vector<char> cache;
			
        public:
            CUart()
            {
                br = 9600;
                pm = pm_none;
                db = data_8bits;
                sb = stop_1bit;
            }
            virtual void SetBaudRate(int value) { br = value; }
            virtual int GetBaudRate() { return br; }
            virtual void SetParityMode(ParityMode value) { pm = value; }
            virtual ParityMode GetParityMode() { return pm; }
            virtual void SetDataBits(DataBits value) { db = value ; }
            virtual DataBits GetDataBits() { return db; }
            virtual void SetStopBits(StopBits value) { sb = value; }
            virtual StopBits GetStopBits() { return sb; }
            virtual int Send(char* addr,int length)
            {
                cache.clear();
                cache.assign(addr,addr+length);
                return 0;
            }
            virtual int ReSend() { return Send(&cache[0],cache.size()); }
            virtual bool Open(DeviceNumber) { return false; }
    };
    class CCanbus:public CSerial,public ICanbus
    {
        protected:
            int id;
            int target_id;
			ISpi* spi;
        public:
            virtual void SetID(const int& value) { id = value; }
            virtual int GetID() { return id; }
            virtual void SetTargetID(const int& value) { target_id = value; }
            virtual int GetTargetID() { return target_id; }
			virtual void SetSPI(ISpi* value){spi = value;}
    };
    class CMCUUart:public CUart,virtual public IMCUUart
    {
        protected:
            WorkMode wm;
            UState state;
            ISpi* spi;
        public:
            CMCUUart()
            {
                wm = WorkMode::passing;
                state = UState::DValid;
            }
            virtual void SetWorkMode(WorkMode value) { wm = value; }
            virtual void SetReceiveLen(int) { }
            virtual void SetReceiveTimeout(int) { }
            virtual UState GetState() { return state; }
            virtual void SetSlaveOperation(bool) { }
            virtual void SetSPI(ISpi* value) { spi = value; }	
    };

    class CSerialManager:public ISerialManager
    {
        static ISerialManager* instance;
        public:
            static ISerialManager* GetInstance();
            virtual IUart* NewM01Uart();
            virtual ISpi* NewM01Spi();
		    virtual ISpi* New_ProjMCU_spi(const std::string&);
            virtual ICanbus* NewM01Canbus();
			virtual ICanbus* New_ProjMCU_canbus(const std::string&);
            virtual IUart9bit* NewM01Uart9bit();
		    virtual std::map<std::string,IMCUUart*> New_ProjMCU_uart(const std::string&);
    };
};

#endif
